home *** CD-ROM | disk | FTP | other *** search
- // PGPServerMemory.cp - AppleShare IP memory management
- //
- // Apple Macintosh Developer Technical Support
- // Written by: Vinne Moscaritolo
- //
- // Copyright (work in progress) Apple Computer, Inc All rights reserved.
- //
- // You may incorporate this sample code into your applications without
- // restriction, though the sample code has been provided "AS IS" and the
- // responsibility for its operation is 100% yours. However, what you are
- // not permitted to do is to redistribute the source as "DSC Sample Code"
- // after having made changes. If you're going to re-distribute the source,
- // we require that you make it clear in the source that the code was
- // descended from Apple Sample Code, but that you've made changes.
- //
-
- #include <OpenTransport.h>
-
- #define FIX_ASLM
- #include <LibraryManager.h>
-
-
- #define PGP_MACINTOSH 1
-
- #include "pgpErrors.h"
- #include "pgpKeys.h"
- #include "pgpMemoryMgr.h"
- #include "pgpUtilities.h"
- #include "pgpFeatures.h"
- #include "pgpHash.h"
- #include "pgpPublicKey.h"
- #include "TPGPException.h"
- #include "TMacException.h"
-
- #include "PGPServerMemory.h"
-
- #define OTAssert( _Msg_, _cond_) ThrowMsgIfNot( _cond_, _Msg_)
-
-
- // ---------------------------------------------------------------------------
- #pragma mark Local Globals?
- // ---------------------------------------------------------------------------
- static Boolean gVirtualMemoryisEnabled = false;
- static PGPNewContextStruct gContextInfo;
- static PGPNewMemoryMgrStruct gMemMgrInfo;
-
- static unsigned long gMemBytesUsed = 0;
- static unsigned long gMemSecureBytesUsed = 0;
-
-
- // ---------------------------------------------------------------------------
- #pragma mark Local Prototypes
- // ---------------------------------------------------------------------------
-
- static void * MemoryAllocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- PGPSize requestSize,
- PGPMemoryMgrFlags flags );
-
- static PGPError MemoryReallocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- void **allocation,
- PGPSize newAllocationSize,
- PGPMemoryMgrFlags flags,
- PGPSize existingSize );
-
- static PGPError MemoryDeallocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- void *allocation,
- PGPSize allocationSize );
-
-
- static void* MemorySecureAllocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- PGPSize requestSize,
- PGPMemoryMgrFlags flags,
- PGPBoolean *isNonPageable );
-
- static PGPError MemorySecureDeallocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- void *allocation,
- PGPSize allocationSize,
- PGPBoolean wasLocked );
-
- static OSStatus InitOpenTransportWithMemoryLimit(void);
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- static void * MemoryAllocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- PGPSize requestSize,
- PGPMemoryMgrFlags flags )
- // ---------------------------------------------------------------------------
- //
- {
- // DebugStr("\p Allocation");
-
- void* p = OTAllocMem(requestSize) ;
-
- if(p) gMemBytesUsed+= requestSize;
-
- if(!p) DebugStr("\p Allocation Failed");
-
- return p;
-
- }
-
- // ---------------------------------------------------------------------------
- static PGPError MemoryReallocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- void **allocation,
- PGPSize newAllocationSize,
- PGPMemoryMgrFlags flags,
- PGPSize existingSize )
- // ---------------------------------------------------------------------------
- //
- {
- void* p;
- // DebugStr("\p Reallocation");
-
- p = OTAllocMem(newAllocationSize);
- if(!p) DebugStr("\p Reallocation Failed");
- if(!p)
- {
- OTFreeMem(p);
- return(kPGPError_OutOfMemory);
- }
- else
- {
- gMemBytesUsed+= (newAllocationSize - existingSize);
-
- OTMemcpy(p, *allocation, existingSize);
- OTFreeMem( *allocation );
- *allocation = p;
- }
-
- return noErr;
- }
-
-
-
- // ---------------------------------------------------------------------------
- static PGPError MemoryDeallocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- void *allocation,
- PGPSize allocationSize )
- // ---------------------------------------------------------------------------
- //
- {
-
- // DebugStr("\p Deallocation");
-
- gMemBytesUsed-=allocationSize;
-
- OTFreeMem( allocation );
- return noErr;
- }
-
-
-
- // ---------------------------------------------------------------------------
- static void* MemorySecureAllocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- PGPSize requestSize,
- PGPMemoryMgrFlags flags,
- PGPBoolean *isNonPageable )
- // ---------------------------------------------------------------------------
- //
- {
- void* p;
-
- // DebugStr("\p Secure Allocation");
-
- p = OTAllocMem(requestSize);
- if(!p) DebugStr("\p Secure Allocation Failed");
-
- if(p)
- {
- if(gVirtualMemoryisEnabled) HoldMemory(p, requestSize);
- gMemSecureBytesUsed+=requestSize;
- }
- return(p);
- }
-
-
- // ---------------------------------------------------------------------------
- static PGPError MemorySecureDeallocationProc ( PGPMemoryMgrRef mgr,
- PGPUserValue userValue,
- void *allocation,
- PGPSize allocationSize,
- PGPBoolean wasLocked )
- // ---------------------------------------------------------------------------
- //
- {
-
- // DebugStr("\p Secure Deallocation");
-
- OTMemzero(allocation, allocationSize);
- if(gVirtualMemoryisEnabled) UnholdMemory(allocation, allocationSize);
- OTFreeMem( allocation );
- gMemSecureBytesUsed-=allocationSize;
-
- return noErr;
- }
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- OSStatus InitializeServerMemory( PGPMemoryMgrRef *memMgr )
- // ---------------------------------------------------------------------------
- //
- {
- OSStatus err;
-
- long response = 0;
-
- // Is virtual memory enabled?
- Gestalt(gestaltVMAttr, &response);
- gVirtualMemoryisEnabled = (response & (1UL << gestaltVMPresent)) != 0;
-
- // Setup opentransport for memory usage
- err = InitOpenTransportWithMemoryLimit();
- if(err != noErr) return err;
-
- // preallocate memory into heap.
- OTFreeMem(OTAllocMem( 64 * 1024));
-
- // setup custom PGP memory manager structure
- gMemMgrInfo.sizeofStruct = sizeof( PGPNewMemoryMgrStruct );
- gMemMgrInfo.allocProc = MemoryAllocationProc;
- gMemMgrInfo.reallocProc = MemoryReallocationProc;
- gMemMgrInfo.deallocProc = MemoryDeallocationProc;
- gMemMgrInfo.secureAllocProc = MemorySecureAllocationProc;
- gMemMgrInfo.secureDeallocProc = MemorySecureDeallocationProc;
- gMemMgrInfo.customValue = nil;
- gMemMgrInfo.reserved = nil;
- gMemMgrInfo.pad[0] = nil;
- gMemMgrInfo.pad[1] = nil;
- gMemMgrInfo.pad[2] = nil;
- gMemMgrInfo.pad[3] = nil;
- gMemMgrInfo.pad[4] = nil;
- gMemMgrInfo.pad[5] = nil;
- gMemMgrInfo.pad[6] = nil;
- gMemMgrInfo.pad[7] = nil;
-
- err = PGPNewMemoryMgrCustom( &gMemMgrInfo, memMgr);
-
- return err;
- }
-
-
- // ---------------------------------------------------------------------------
- void FinalizeServerMemory( PGPMemoryMgrRef memMgr )
- // ---------------------------------------------------------------------------
- //
- {
- PGPFreeMemoryMgr(memMgr);
-
- CloseOpenTransport();
- CleanupLibraryManager();
- }
-
- #pragma mark -
-
- // from Quinn's StreamLogWatcher.c
- //
- // InitOpenTransportWithMemoryLimit Big Picture
- // --------------------------------------------
- //
- // The LogEngine uses the OT memory allocation routines
- // (OTAllocMem, OTFreeMem) to allocate space for log entries in
- // the notifier. This memory comes from an ASLM memory pool
- // that OT creates for us when we call InitOpenTransport. However,
- // this pool has some bad characteristics:
- //
- // 1. The pool starts off very small, and only grows when we allocate
- // memory from it. As we do all our allocation from our notifier
- // (which is interrupt time with respect to the system Memory Manager)
- // the pool can't grow immediately. So the pool will often run
- // be full (ie OTAllocMem will return nil) even though the application
- // has plenty of memory. The pool will later grow, but we've already
- // dropped the log entry on the floor.
- //
- // 2. Because the pool starts off small and grows by pieces, we get
- // an extremely fragmented pool. While this works, its definitely
- // sub-optimal.
- //
- // 3. If we're being hammered by strlog (ie people are calling strlog a
- // lot), the pool will keep growing and there's nothing to stop
- // the pool consuming our entire application heap. When it does so,
- // various toolbox routines (eg QuickDraw) fail ungracefully, ie
- // SysError(25).
- //
- // There are a number of steps in my solution to this. The first step
- // is to call InitLibraryManager myself. This allows me to specify
- // the size of the pool. InitOpenTransport notices that I have inited ASLM
- // myself and doesn't do it itself. Thus OTAllocMem gets its memory from
- // whatever pool ASLM created. This gets around problems 1 and 2.
- //
- // The second step is to create a subsidiary zone within my application heap
- // and specify that ASLM should create its pool in that zone (by supplying
- // kCurrentZone to InitLibraryManager). Thus the pool can grow up to the
- // point where the memory in the subsidiary zone is exhausted. At that point,
- // the pool will no longer grow. So the pool will not steal memory from
- // the main application heap. This gets around problem 3.
- //
- // There are a number of other ways I could have achieved the same results.
- // The ASLM memory manager is very flexible. For example, I could have removed
- // OT's TPoolNotifier from the pool, which would prevent the pool from growing.
- // However, this solution does not require me to use any ASLM C++ stuff,
- // which makes the code more compiler independent.
-
- enum {
- kBytesReservedForToolboxInApplicationZone = 100L * 1024L,
- // This value represents the minimum number of contiguous
- // bytes that should remain in the application heap after
- // we've created the subsidiary zone.
-
- kBytesReservedForASLMInSubsidaryzone = 2048,
- // This value represents the number of bytes in the subsidiary
- // zone we should leave lying around for general purpose ASLM
- // use. The remaining bytes in the subsidiary zone are
- // dedicated to the ASLM memory pool, ie are passed as the pool
- // size to InitLibraryManager.
-
- kMinimumBytesForUsInSubsidiaryZone = 10 * 1024
- // This value represents the minimum pool size we pass to
- // InitLibraryManager. If we can't create a pool of at least
- // this size, the application doesn't start up.
- };
-
-
- static OSStatus InitOpenTransportWithMemoryLimit(void)
- // See above for an explanation of the big picture here.
- {
- OSStatus err;
- SInt32 junkTotalFree;
- SInt32 contigFree;
- SInt32 zoneSize;
- Ptr gSubsidiaryZone;
- THz oldZone;
-
- // Debugger();
-
- // First call the system Memory Manager to determine the largest
- // contiguous block in the heap.
-
- PurgeSpace(&junkTotalFree, &contigFree);
-
- // If it's too small for our toolbox needs, bail out.
-
- err = noErr;
- if (contigFree < kBytesReservedForToolboxInApplicationZone) {
- err = memFullErr;
- }
-
- // Now calculate the size of the zone we're going to create.
- // It's the size of the largest contiguous block, minus
- // the size of we reserve for toolbox needs, rounded to the nearest KB.
- // If the zone size isn't big enough enough to hold our minimum
- // pool size and the amount we reserve for ASLM, bail out.
-
- if (err == noErr) {
- zoneSize = contigFree - kBytesReservedForToolboxInApplicationZone;
- zoneSize = zoneSize & ~0x003FF;
- if (zoneSize < (kBytesReservedForASLMInSubsidaryzone + kMinimumBytesForUsInSubsidiaryZone)) {
- err = memFullErr;
- }
- }
-
- // Allocate the memory for our zone and create a zone in that
- // block. Then init ASLM, telling it to create a pool that
- // takes up the entire zone (minus the ASLM overhead factor)
- // in the current zone, ie the zone we just created. Finally,
- // initialise OT. OT will see that we've inited ASLM and use
- // the pool that ASLM created (in the zone we created) for
- // satisfying OTAllocMem requests.
-
- if (err == noErr) {
- gSubsidiaryZone = NewPtr(zoneSize);
- OTAssert("InitOpenTransportWithMemoryLimit: Couldn't get the memory but preflight says its there", gSubsidiaryZone != nil);
- OTAssert("InitOpenTransportWithMemoryLimit: Just being paranoid", MemError() == noErr);
-
- oldZone = GetZone();
-
- InitZone(nil, 16, gSubsidiaryZone + zoneSize, gSubsidiaryZone);
- OTAssert("InitOpenTransportWithMemoryLimit: InitZone failed", MemError() == noErr);
-
- // InitZone sets the current zone to the newly created zone,
- // so I don't have to do it myself.
-
- err = InitLibraryManager(zoneSize - kBytesReservedForASLMInSubsidaryzone, kCurrentZone, kNormalMemory);
- if (err == noErr) {
- err = InitOpenTransport();
- if (err != noErr) {
- CleanupLibraryManager();
- }
- }
-
- SetZone(oldZone);
- }
-
- return err;
- }
-